Micron Document
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| SparkN0de-git | SparkN0de |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


Commit 45c031d34308c8e9f23e69e1ececcb0455dac0c2


Parents : f6158ba 3ce348d
Author : Mark Qvist <bc7291552be7a58f361522990465165c>
Date : 2026-05-21T01:27:51+02:00

Merged The Deluxe Nomadnet Expansion Pack from Zenith

Diff

diff --cc nomadnet/ui/textui/Channels.py
index 143dd0d,afa568b..687ce96
--- a/nomadnet/ui/textui/Channels.py
+++ b/nomadnet/ui/textui/Channels.py
@@@ -13,12 -13,11 +13,13 @@@ from nomadnet.ui.textui.MicronParser im
from RNS.Utilities.rngit.util import MarkdownToMicron
from RNS.Utilities.rngit.highlight import SyntaxHighlighter
from .MicronParser import markup_to_attrmaps
-from nomadnet.util import strip_modifiers, sanitize_name
+from nomadnet.util import sanitize_name, strip_modifiers, strip_micron
+from nomadnet.util import strip_escaped_micron, unescape_micron, strip_non_formatting_tags
+ from nomadnet.vendor.Scrollable import Scrollable, ScrollBar
-theme_dark = { "ts": "888",
+theme_dark = { "text": "ddd",
+ "ts": "888",
"nick_self": "6c5",
"nick_peer": "3cd",
"notice": "fd3",
@@@ -448,24 -575,60 +584,62 @@@ class RoomWidget(urwid.WidgetWrap)
return
members = self.hub.get_members(self.room)
own_hash = self.app.identity.hash if self.app.identity is not None else None
- names = []
+ def _safe_name(raw):
+ if not raw: return ""
+ try:
+ if self.app.config["textui"]["sanitize_names"]:
+ return sanitize_name(str(raw)) or ""
+ return strip_modifiers(str(raw)) or ""
+ except Exception:
+ return str(raw or "")
+
+ entries = []
for m in members:
- if own_hash is not None and m == own_hash:
- names.append((self.hub.display_name_for(m), True))
- else:
- names.append((self.hub.display_name_for(m), False))
- names.sort(key=lambda x: x[0].lower())
- entries.append((_safe_name(self.hub.display_name_for(m)), m, own_hash is not None and m == own_hash))
++ safe_name = _safe_name(self.hub.display_name_for(m))
++ safe_name = safe_name[:15]+"…" if len(safe_name) > 16 else safe_name
++ entries.append((safe_name, m, own_hash is not None and m == own_hash))
+ entries.sort(key=lambda x: x[0].lower())
- rows = [urwid.Text(" "+str(len(names))+" user"+("s" if len(names) != 1 else ""))]
- for name, is_self in names:
- name = sanitize_name(name); name = name[:15]+"…" if len(name) > 16 else name
+ prev_focus_key = None
+ try:
+ prev_idx = walker.focus
+ if prev_idx is not None and 0 <= prev_idx < len(walker):
+ prev_focus_key = getattr(walker[prev_idx], "user_hash", None)
+ except Exception:
+ prev_focus_key = None
+
+ rows = [urwid.Text(" "+str(len(entries))+" user"+("s" if len(entries) != 1 else ""))]
+ for name, peer_hash, is_self in entries:
if is_self:
- rows.append(urwid.AttrMap(urwid.Text(" "+g["arrow_r"]+" "+name), "list_trusted"))
+ label = " "+g["arrow_r"]+" "+name
+ style = "list_trusted"
else:
- rows.append(urwid.AttrMap(urwid.Text(" "+g["peer"]+" "+name), "connected_status"))
- if not names:
+ label = " "+g["peer"]+" "+name
+ style = "connected_status"
+ entry = ChannelListEntry(label)
+ urwid.connect_signal(entry, "click", self.display.show_user_info, (self.hub, peer_hash, name))
+ row = urwid.AttrMap(entry, style, "list_focus")
+ row.user_hash = peer_hash
+ rows.append(row)
+ if not entries:
rows.append(urwid.Text(" (no members)"))
- self.users_pile.contents = [(w, self.users_pile.options()) for w in rows]
+
+ walker[:] = rows
+
+ new_focus = None
+ if prev_focus_key is not None:
+ for idx, w in enumerate(walker):
+ if getattr(w, "user_hash", None) == prev_focus_key:
+ new_focus = idx
+ break
+ if new_focus is None:
+ for idx, w in enumerate(walker):
+ if hasattr(w, "user_hash"):
+ new_focus = idx
+ break
+ if new_focus is not None:
+ try: walker.set_focus(new_focus)
+ except Exception: pass
def _update_peer_info(self):
if self.hub is None or self.room is None:
@@@ -909,17 -1086,75 +1097,43 @@@ class _ChatLinkDelegate
except Exception as e:
RNS.log("Could not open page link: "+str(e), RNS.LOG_ERROR)
-def strip_micron(text):
- text = re.sub(r'`[FB][0-9a-fA-F]{3}', '', text)
- text = re.sub(r'`[FB]T[0-9a-fA-F]{6}', '', text)
- text = re.sub(r'`[!*_=]', '', text)
- text = re.sub(r'`f`b', '', text)
- text = re.sub(r'`f', '', text)
- text = re.sub(r'`b', '', text)
- text = re.sub(r'`<', '', text)
- text = re.sub(r'`>', '', text)
- text = re.sub(r'`{', '', text)
- return text
-
-def strip_escaped_micron(text):
- text = re.sub(r'¦[FB][0-9a-fA-F]{3}', '', text)
- text = re.sub(r'¦[FB]T[0-9a-fA-F]{6}', '', text)
- text = re.sub(r'¦[!*_=]', '', text)
- text = re.sub(r'¦f`b', '', text)
- text = re.sub(r'¦f', '', text)
- text = re.sub(r'¦b', '', text)
- text = re.sub(r'¦<', '', text)
- text = re.sub(r'¦>', '', text)
- text = re.sub(r'¦{', '', text)
- return text
-
-def unescape_micron(text):
- text = re.sub(r'¦([FB][0-9a-fA-F]{3})', r'`\1', text)
- text = re.sub(r'¦([FB]T[0-9a-fA-F]{6})', r'`\1', text)
- text = re.sub(r'¦([!*_=])', r'`\1', text)
- text = re.sub(r'¦(f`b)', r'`\1', text)
- text = re.sub(r'¦(f)', r'`\1', text)
- text = re.sub(r'¦(b)', r'`\1', text)
- text = re.sub(r'¦(<)', r'`\1', text)
- text = re.sub(r'¦(>)', r'`\1', text)
- text = re.sub(r'¦({)', r'`\1', text)
- return text
-
-def strip_non_formatting_tags(text):
- text = re.sub(r'`<', '', text)
- text = re.sub(r'`>', '', text)
- text = re.sub(r'`{', '', text)
- return text
-
-mdc = MarkdownToMicron(max_width=80, syntax_highlighter=SyntaxHighlighter(), url_scope=None)
+
+ _MOTD_ROOM_RE = re.compile(r"(?<!\[)(?<!\w)#([A-Za-z0-9][A-Za-z0-9_\-]{0,62})")
+
+ def _linkify_motd(text):
+ if not text:
+ return text or ""
+ def repl(m):
+ name = m.group(1)
+ return "`["+m.group(0)+"`room://"+name+"]"
+ return _MOTD_ROOM_RE.sub(repl, text)
+
+
+ def _is_joinpart_system(m):
+ if getattr(m, "kind", None) != "system":
+ return False
+ text = (getattr(m, "text", "") or "").strip()
+ if not text:
+ return False
+ if text.startswith("You "):
+ return False
+ return text.endswith(" joined") or text.endswith(" left")
+
+ def _collapsed_joinpart_widget(app, n):
+ label = " ⋯ "+str(n)+" join/leave event"+("" if n == 1 else "s")+" ⋯"
+ return urwid.Padding(urwid.AttrMap(urwid.Text(label, align=urwid.CENTER), "irc_system"), left=1)
+
+def get_nick_color(sender_hash, theme, app, shift=15):
+ if app.rrc_nick_colors_theme: nick_colors = app.rrc_nick_colors_theme
+ else: nick_colors = theme["nick_colors"]
+ if type(sender_hash) == str:
+ try: sender_hash = sender_hash.encode("utf-8")
+ except: pass
+ if not type(sender_hash) == bytes: return theme["nick_peer"]
+ return nick_colors[(int.from_bytes(sender_hash)+shift)%len(nick_colors)]
+
+room_nick_src_cache = {}
+mdc = MarkdownToMicron(max_width=80, syntax_highlighter=SyntaxHighlighter(), url_scope=None)
def _message_widget(app, hub, m, link_delegate=None):
t = theme_dark if app.config["textui"]["theme"] == nomadnet.ui.TextUI.THEME_DARK else theme_light
g = app.ui.glyphs
diff --cc nomadnet/ui/textui/Conversations.py
index 49bb6e7,d48edc6..3c0dc5a
--- a/nomadnet/ui/textui/Conversations.py
+++ b/nomadnet/ui/textui/Conversations.py
@@@ -1726,10 -2572,15 +2587,16 @@@ class LXMessageWidget(urwid.WidgetWrap)
pile_widgets.append(self.progress_attr)
self._start_progress_poll()
- pile_widgets.append(urwid.Text(indented))
+ if markdown: pile_widgets.append(content_pile)
+ else: pile_widgets.append(urwid.Text(indented))
if has_attachments and cached_names:
+ if inbound_untrusted:
+ pile_widgets.append(urwid.AttrMap(
+ urwid.Text(" "+g["warning"]+" This attachment came from a peer that's untrusted. Be careful when opening it."),
+ "list_untrusted",
+ ))
+
att_file_idx = 0
for atype, aname, *arest in cached_names:
glyph = g["file"] if atype == "file" else g[atype]


──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────